﻿using log4net.Appender;
using log4net.Config;
using log4net.Layout;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CPPEI
{
    public static class Logger
    {
        private static string s_logOutputDirectory;
        private static Dictionary<string, log4net.ILog> s_loggerDict = new Dictionary<string, log4net.ILog>();
        private static IAppender s_allAppender;

        private static readonly string TAG_ALL = "ALL";
        private static object s_lockObj = new object();

        /// <summary>
        /// 获得log4net的日志器
        /// </summary>
        /// <param name="tag"></param>
        /// <returns></returns>
        private static log4net.ILog GetLog(string tag)
        {
            string upperTAG = tag.ToUpper();
            if (s_loggerDict.ContainsKey(upperTAG))
            {
                return s_loggerDict[upperTAG];
            }
            else
            {
                if (string.IsNullOrEmpty(s_logOutputDirectory))
                {
                    return null;
                }
                lock (s_lockObj)
                {
                    if (s_loggerDict.ContainsKey(upperTAG))
                    {
                        return s_loggerDict[upperTAG];
                    }
                    log4net.ILog log = log4net.LogManager.GetLogger(upperTAG);
                    log4net.Repository.Hierarchy.Logger logger = (log4net.Repository.Hierarchy.Logger)log.Logger;
                    logger.Level = logger.Hierarchy.LevelMap["ALL"];
                    if (!string.Equals(upperTAG, TAG_ALL))
                    {
                        logger.AddAppender(GetRollingFileAppender(s_logOutputDirectory, upperTAG));
                    }
                    logger.AddAppender(s_allAppender);
                    //logger.AddAppender(GetConsoleAppender(tag));
                    s_loggerDict.Add(upperTAG, log);
                    return log;
                }
            }
        }

        /// <summary>
        /// 初始化日志接口，加载log4net的配置文件
        /// </summary>
        /// <param name="configFile"></param>
        [Obsolete("暂不使用")]
        private static void Init(string configFile)
        {
            FileInfo fileinfo = new FileInfo(configFile);
            log4net.Config.XmlConfigurator.Configure(fileinfo);
#if DEBUG
            System.Diagnostics.Debug.WriteLine(string.Format("{0}\t{1}", "Init", configFile));
#endif
        }

        /// <summary>
        ///  根据日志路径初始化
        /// </summary>
        /// <param name="directory"></param>
        private static void InitByLogDirectory(string directory)
        {
            BasicConfigurator.Configure(GetConsoleAppender());
            
            s_logOutputDirectory = directory;
            s_allAppender = GetRollingFileAppender(s_logOutputDirectory, TAG_ALL);
        }

        static Logger()
        {
            s_logOutputDirectory = System.Configuration.ConfigurationManager.AppSettings["CPPEI.LogDirectory"];

            BasicConfigurator.Configure(GetDebugAppender());

            s_allAppender = GetRollingFileAppender(s_logOutputDirectory, TAG_ALL);

            //BasicConfigurator.Configure(s_allAppender);
        }

        /// <summary>
        /// 设置tag的文件输出格式为单一文件,只能初始化一次
        /// </summary>
        /// <param name="tag"></param>
        public static void ConfigSingletonFileAppender(string tag)
        {
            string upperTAG = tag.ToUpper();
            if (s_loggerDict.ContainsKey(upperTAG))
            {
                return;
            }
            else
            {
                if (string.IsNullOrEmpty(s_logOutputDirectory))
                {
                    return;
                }
                lock (s_lockObj)
                {
                    if (s_loggerDict.ContainsKey(upperTAG))
                    {
                        return;
                    }
                    log4net.ILog log = log4net.LogManager.GetLogger(upperTAG);
                    log4net.Repository.Hierarchy.Logger logger = (log4net.Repository.Hierarchy.Logger)log.Logger;
                    logger.Level = logger.Hierarchy.LevelMap["ALL"];
                    if (!string.Equals(upperTAG, TAG_ALL))
                    {
                        logger.AddAppender(GetSingletonFileAppender(s_logOutputDirectory, upperTAG));
                    }
                    logger.AddAppender(s_allAppender);
                    //logger.AddAppender(GetConsoleAppender(tag));
                    s_loggerDict.Add(upperTAG, log);
                }
            }
        }

        /// <summary>
        /// 使用文本记录异常日志
        /// </summary>
        /// <Author>zyzheng</Author>
        /// <date>2014-4-16</date>
        private static RollingFileAppender GetRollingFileAppender(string logDirectory, string tag)
        {
            if(string.IsNullOrEmpty(logDirectory))
            {
                return null;
            }
            /*
             *   <param name="File" value="Logs\\Error\\" /><!-- 输出到什么目录-->
                <param name="AppendToFile" value="true" /><!-- 是否覆写到文件中-->
                <!--<param name="MaxSizeRollBackups" value="100" />--><!-- 备份文件的个数-->
                <!--<param name="MaxFileSize" value="10240" />--><!-- 单个日志文件最大的大小-->
                <param name="StaticLogFileName" value="false" /><!-- 是否使用静态文件名-->
                <param name="DatePattern" value="yyyy-MM-dd&quot;.log&quot;" /><!-- 日志文件名-->
                <param name="RollingStyle" value="Date" />
                <layout type="log4net.Layout.PatternLayout">
                  <param name="ConversionPattern" value="%d  [%t] %p  %m %newline"  />
                </layout>
             */
            //string txtLogPath = string.Empty;
            //txtLogPath = Path.Combine(logDirectory, tag + "\\");

            RollingFileAppender fileAppender = new RollingFileAppender();
            fileAppender.Name = string.Format("{0}Appender", tag);
            fileAppender.File = logDirectory;// string.Format("{0}{1}\\", logDirectory, tag);
            fileAppender.AppendToFile = true;
            fileAppender.StaticLogFileName = false;
            fileAppender.DatePattern = string.Format("yyyy-MM-dd\"\\\\{0}.log\"", tag);  //"yyyy-MM-dd\"\\.log\"";
            fileAppender.RollingStyle = RollingFileAppender.RollingMode.Composite;
            fileAppender.MaxFileSize = 1024 * 1024;
            fileAppender.MaxSizeRollBackups = 1024;
            fileAppender.LockingModel = new log4net.Appender.FileAppender.MinimalLock();

            PatternLayout patternLayout = new PatternLayout();
            if(string.Equals(tag, TAG_ALL, StringComparison.CurrentCultureIgnoreCase))
            {
                patternLayout.ConversionPattern = "%d [%t] %p %m %newline";
            }
            else
            {
                patternLayout.ConversionPattern = "%d [%t] %p %logger %m %newline";
            }
            patternLayout.ActivateOptions();
            fileAppender.Layout = patternLayout;

            //选择UTF8编码，确保中文不乱码。
            fileAppender.Encoding = Encoding.UTF8;

            fileAppender.ActivateOptions();
            return fileAppender;
        }

        private static FileAppender GetSingletonFileAppender(string logDirectory, string tag)
        {
            if (string.IsNullOrEmpty(logDirectory))
            {
                return null;
            }
            FileAppender fileAppender = new FileAppender();
            fileAppender.Name = string.Format("{0}SingletonAppender", tag);
            fileAppender.File = string.Format("{0}{1}.log", logDirectory, tag);
            fileAppender.AppendToFile = true;
            fileAppender.LockingModel = new log4net.Appender.FileAppender.MinimalLock();

            PatternLayout patternLayout = new PatternLayout();
            if (string.Equals(tag, TAG_ALL, StringComparison.CurrentCultureIgnoreCase))
            {
                patternLayout.ConversionPattern = "%d [%t] %p %m %newline";
            }
            else
            {
                patternLayout.ConversionPattern = "%d [%t] %p %logger %m %newline";
            }
            patternLayout.ActivateOptions();
            fileAppender.Layout = patternLayout;

            //选择UTF8编码，确保中文不乱码。
            fileAppender.Encoding = Encoding.UTF8;

            fileAppender.ActivateOptions();
            return fileAppender;
        }

        private static DebugAppender GetDebugAppender()
        {
            DebugAppender appender = new DebugAppender();
            appender.Name = "__DEBUG__Appender";

            PatternLayout patternLayout = new PatternLayout();
            patternLayout.ConversionPattern = "%d [%t] %p %logger %m %newline";
            patternLayout.ActivateOptions();
            appender.Layout = patternLayout;

            appender.ActivateOptions();
            return appender;
        }

        private static ConsoleAppender GetConsoleAppender()
        {
            ConsoleAppender appender = new ConsoleAppender();
            appender.Name = "ConsoleAppender";

            PatternLayout patternLayout = new PatternLayout();
            patternLayout.ConversionPattern = "%d [%t] %p %logger %m %newline";
            patternLayout.ActivateOptions();
            appender.Layout = patternLayout;

            appender.ActivateOptions();
            return appender;
        }

        #region info
        public static void Info(string message)
        {
            Info(TAG_ALL, message);
        }

        /// <summary>
        /// 信息日志
        /// </summary>
        /// <param name="tag">获取信息Logger的名字</param>
        /// <param name="message">信息消息</param>
        public static void Info(string tag, string message)
        {
            log4net.ILog loginfo = GetLog(tag);
            if (loginfo == null)
            {
                return;
            }
            loginfo.Info(message);
        }

        #endregion

        #region debug
        public static void Debug(string message)
        {
            Debug(TAG_ALL, message);
        }

        /// <summary>
        /// 输出日志
        /// </summary>
        /// <param name="tag">获取输出Logger的名字</param>
        /// <param name="message">输出信息</param>
        public static void Debug(string tag, string message)
        {
            log4net.ILog logdebug = GetLog(tag);
            if (logdebug == null)
            {
                return;
            }
            logdebug.Debug(message);
        }

        #endregion

        #region warning
        public static void Warning(string message)
        {
            Warning(TAG_ALL, message);
        }

        /// <summary>
        /// 警告日志
        /// </summary>
        /// <param name="tag">获取警告Logger的名字</param>
        /// <param name="message">警告信息</param>
        public static void Warning(string tag, string message)
        {
            log4net.ILog logwarning = GetLog(tag);
            if (logwarning == null)
            {
                return;
            }
            //Console.ForegroundColor = ConsoleColor.Yellow;
            logwarning.Warn(message);
            //Console.ForegroundColor = ConsoleColor.White;
        }

        #endregion

        #region error
        public static void Error(string message)
        {
            Error(TAG_ALL, message);
        }

        /// <summary>
        /// 错误日志
        /// </summary>
        /// <param name="tag">获取错误logger的名字</param>
        /// <param name="message">错误消息</param>
        public static void Error(string tag, string message)
        {
            log4net.ILog logerror = GetLog(tag);
            if (logerror == null)
            {
                return;
            }
            Console.ForegroundColor = ConsoleColor.Red;
            logerror.Error(message);
            Console.ForegroundColor = ConsoleColor.White;
        }
        #endregion
    }
}
